package simorg;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

class DatabaseInterface extends DatabaseAccess {
	static DatabaseInterface s_singleton = new DatabaseInterface();

	public static DatabaseInterface getSingleton() {
		return s_singleton;
	}

	public static void main(final String[] a_args) {
		System.out.println("Testing export.");

		final DatabaseInterface dbInterface = new DatabaseInterface();

		try {
			dbInterface.loadAll();
		} catch (final SQLException ex) {
			ex.printStackTrace();
		}

		/*
		 * System.out.println( "Testing strings." ); for( int i = 2; i <
		 * dbInterface.m_stringSet.size() + 2; i++ ) { System.out.println(
		 * "String " + i + ": " + dbInterface.getString( i ) ); } //
		 */

		/*
		 * System.out.println( "Testing unknowns." ); for( Unknown curUnknown :
		 * dbInterface.getAllUnknowns() ) { //unknown.dbgListResults();
		 * System.out.println( curUnknown.getFullName() ); } //
		 */

		/*
		 * System.out.println( "Testing tests." ); for( int i = 2; i <
		 * dbInterface.m_numClassificationTests +
		 * dbInterface.m_numDerivativeTests + 1; i++ ) { Test test =
		 * dbInterface.getTest( i );
		 * 
		 * if( test == null ) { System.out.println( "Test: null" ); } else {
		 * System.out.println( "Test: " + test.getFullName() ); } } //
		 */

		// *
		System.out.println("Testing results. "
				+ dbInterface.m_resultsSet.size());
		for (final TestResult result : dbInterface.m_resultsSet) {
			result.dbgListTests();
		}
		// */

		System.out.println("Done.");
	}

	private int m_numClassificationTests = 0;

	private int m_numDerivativeTests = 0;

	private int m_numStrings = 0;

	private int m_numUnknowns = 0;

	private final Set<TestResult> m_resultsSet = new HashSet<TestResult>();

	private final Set<SimString> m_stringSet = new HashSet<SimString>();

	private final Set<Test> m_classificationTestSet = new HashSet<Test>();

	private final Set<Test> m_derivativeTestSet = new HashSet<Test>();

	private final Set<Unknown> m_unknownSet = new HashSet<Unknown>();

	private DatabaseInterface() {
	}

	public TestResult addResult(final int a_resultId, final int a_testId) {

		// if the result exists, get it; else, make it
		TestResult result = getResult(a_resultId);
		if (result == null) {
			result = new TestResult(a_resultId);
			m_resultsSet.add(result);
		}

		// find the test
		final Test targetTest = getClassificationTest(a_testId);

		// add the test to the result
		result.addTest(targetTest);

		return result;
	}

	public ArrayList<Test> getAllTests() {
		final ArrayList<Test> allTests = new ArrayList<Test>(
				m_classificationTestSet);
		allTests.addAll(m_derivativeTestSet);

		// sort the tests by type and ID
		Collections.sort(allTests);

		return allTests;
	}

	public ArrayList<Unknown> getAllUnknowns() {
		final ArrayList<Unknown> unknownList = new ArrayList<Unknown>(
				m_unknownSet);

		// sort the unknowns
		Collections.sort(unknownList);

		return unknownList;
	}

	public Test getClassificationTest(final int a_id) {
		for (final Test test : m_classificationTestSet) {
			if (test.getId() == a_id) {
				return test;
			}
		}

		return null;
	}

	public Test getDerivativeTest(final int a_id) {
		for (final Test test : m_derivativeTestSet) {
			if (test.getId() == a_id) {
				return test;
			}
		}

		return null;
	}

	public TestResult getResult(final int a_id) {
		for (final TestResult result : m_resultsSet) {
			if (result.getResult() == a_id) {
				return result;
			}
		}

		return null;
	}

	public String getString(final int a_id) {
		// if( a_id >= m_numStrings ) return null;

		for (final SimString str : m_stringSet) {
			if (str.getId() == a_id) {
				return str.toString();
			}
		}

		return "No string with ID #" + a_id;
	}

	// get test by raw ID (database has classification tests listed first)
	public Test getTest(final int a_id) {
		if (a_id <= m_numClassificationTests) {
			return getClassificationTest(a_id);
		} else {

			// +2 because derivative tests begin with #2
			// i.e. if T10 is the last class test, test #11 is D( 11 - 10 + 1 )
			// = D2
			return getDerivativeTest(a_id - m_numClassificationTests + 1);
		}
	}

	public Unknown getUnknown(final int a_id) {
		if (a_id >= m_numUnknowns) {
			return null;
		}

		for (final Unknown unknown : m_unknownSet) {
			if (unknown.getId() == a_id) {
				return unknown;
			}
		}

		return null;
	}

	private ResultSet getValues(final Table a_table) throws SQLException {
		final int tableId = a_table.ordinal();
		final String sqlString = "SELECT * FROM " + TABLE_NAME[tableId];

		return sqlExecuteQuery(sqlString);
	}

	public void loadAll() throws SQLException {
		linkToDatabase();

		loadStrings();
		loadTests();
		loadUnknowns();
	}

	private void loadStrings() throws SQLException {
		System.out.println("Loading strings.");

		final ResultSet results = getValues(Table.STRING);

		while (results.next()) {
			final int id = results.getInt(1);
			final String str = results.getString(2);
			// System.out.println( "| String: '" + str + "' |" );
			m_stringSet.add(new SimString(id, str));
			m_numStrings++;
		}
	}

	private void loadTests() throws SQLException {
		System.out.println("Loading classification tests.");

		ResultSet results = getValues(Table.CLASSIFICATION_TESTS);

		while (results.next()) {
			final Test test = new Test(results, results.getInt(1), false);
			// System.out.println( "| Classification Test: '" + test.getName() +
			// "' (" + test.getId() + ") |" );
			m_classificationTestSet.add(test);
			m_numClassificationTests++;
		}

		System.out.println("Loading derivative tests.");

		results = getValues(Table.DERIVATIVE_TESTS);

		while (results.next()) {
			final Test test = new Test(results, results.getInt(1), true);
			// System.out.println( "| Derivative Test: '" + test.getName() + "'
			// (" + test.getId() + ") |" );
			m_derivativeTestSet.add(test);
			m_numDerivativeTests++;
		}
	}

	public void loadUnknowns() throws SQLException {
		System.out.println("Loading unknowns.");

		final ResultSet results = getValues(Table.UNKNOWNS);

		while (results.next()) {
			final Unknown unknown = new Unknown(results);
			m_unknownSet.add(unknown);
			m_numUnknowns++;
		}
	}
}
